#!/usr/bin/lua
---------------------------------------------------------------------
-- FastCGI loader
-- This script should be run by the FastCGI module or embedded in a
-- executable
---------------------------------------------------------------------
local prog_arg = arg or {...}

local function try_require(x)
	local r, o = pcall(require, x)
	return r and o or nil
end

local lfcgi = try_require'lfcgi'
local lfs = try_require'lfs'
local accept

if lfcgi then
	io.stdout = lfcgi.stdout
	io.stderr = lfcgi.stderr
	io.stdin = lfcgi.stdin
	os.getenv = lfcgi.getenv
	accept = lfcgi.accept
	print = function (...)
		local n = select('#', ...)
		local arg = {...}
		for i=1,n do
			io.stdout:write(tostring(arg[i]), i < n and "\t" or "\n")
		end
	end
else
	accept = (function(runs)
		return function()
			runs = runs - 1
			return runs
		end
	end)(1)
end

local function report_to_client(x)
	--io.stdout:write("Status: 500 Server Error\r\n")
	io.stdout:write("Status: 200 OK\r\n")
	io.stdout:write("Content-Type: text/plain\r\n")
	io.stdout:write("\r\n")
	io.stdout:write(x)
  for k,v in pairs(lfcgi.environ()) do print(k,v) end
end

local function report(x)
	--io.stderr:write(x)
	report_to_client(x)
end


local function script_mtime(file)
	if not lfs then return os.time()+1 end
	local attr = lfs.attributes(file)
	local mtime = attr and attr.modification
	return mtime or 0
end

local cached_objects=setmetatable({},{__mode='kv'})
local _G_mt = {__index = _G}

local function run(file)
	local e
	local object = cached_objects[file] or {}
	local mtime = script_mtime(file)

	if not object.bytecode or object.mtime < mtime then
		object.bytecode, e = loadfile(file)
		object.mtime = mtime
	end

	if not object.bytecode then report(e) 
	else
		local x,e = pcall(setfenv(object.bytecode, setmetatable({}, _G_mt)))
		if not x then 
			cached_objects[file] = nil
			report(e) 
		else cached_objects[file] = object end
	end
end

local init_result
if prog_arg and prog_arg[1] then
  local s = loadfile(prog_arg[1])
  if s then 
    local ok, ret = xpcall(s, function(e) init_result = e end)
  end
end

while accept() >= 0 do
  if init_result then 
		io.stdout:write('Content-Type: text/plain\r\n\r\n')
    io.stdout:write(ini_result)
    return
  end
	local script_filename = os.getenv'SCRIPT_FILENAME'
	local path_translated = os.getenv'PATH_TRANSLATED' or ""
	local script_name = os.getenv'SCRIPT_NAME' or ""
  local docroot = os.getenv'DOCUMENT_ROOT'
	local script_base_name = script_name:match("[^/]*$")
	local path_info = os.getenv'PATH_INFO' or '/'
  local base = path_info:match("[^/]*$") or ""
	if not path_info then 
		if script_filename then run(script_filename)
		else
			io.stdout:write('Content-Type: text/plain\r\n\r\nluacgi!\r\n')
		end
	else
		local b, e = path_info:find(script_name)
		if e then 
			if script_filename then
        if script_filename:sub(-#base) == base then
				  script_filename = script_filename:sub(1,  -1 - (#path_info - e)) 
        end
				run(script_filename)
			else
				--script_filename = path_translated:sub(1,  -1 - (#path_info - e)) 
        if docroot then
          script_filename = docroot .. script_name  
        else
				  script_filename = path_translated:sub(1,  -1 - (#path_info - e)) 
        end
				run(script_filename)
			end
		elseif script_filename then
			if script_filename:find("cgi$") then
				run(path_translated)
			else
				run(script_filename)
			end
		else
			run(path_translated)
		end
	end
end 
